from dbutils.pooled_db import PooledDB  # 同步连接池
import pymysql

# 导入几个常用的类型标注工具
# List：标注 “列表” 类型，指定列表中元素的类型。
# Tuple：标注 “元组” 类型，指定元组中各位置元素的类型。
# ptional：标注 “可选类型”，表示某个参数或变量可以是指定类型，也可以是 None。
# Any：标注 “任意类型”，表示不限制具体类型（用于无法或无需明确类型的场景）
from typing import List, Tuple, Optional, Any
import aiomysql #协程异步连接池
# 日志
import logging
logger = logging.getLogger(__name__)


from sql_yu_ju import SQL_YU_JI_l
import asyncio  #协程异步

# MYSQL协程异步连接池
class AsyncMYSQL:
    """异步 MySQL 数据库操作类"""

    # 数据库连接配置
    __host = '192.168.1.88'
    __port = 3306
    __database = 'zhi_neng_wang_guan'
    __user = 'a18222970'
    __password = 'cx123100'

    # 异步连接池实例
    '''
     __pool: Optional[aiomysql.Pool] = None
    声明一个类级别的私有变量 __pool，它可以存储 aiomysql 连接池实例（aiomysql.Pool 类型）或 None（未初始化状态），
    初始值为 None，用于管理数据库连接池的生命周期（创建、使用、关闭）。这种设计确保了连接池的安全复用和状态可控，
    是异步数据库操作中常见的资源管理模式
     : 在此处是类型提示的语法符号，用于为变量 __pool 声明其预期的类型（aiomysql.Pool 或 None）
    '''
    __pool: Optional[aiomysql.Pool] = None

    '''
    cls 是 类方法（Class Method） 的第一个参数，代表类本身（即 AsyncMYSQL_CZ 类）。
    类方法需要通过 @classmethod 装饰器声明，其核心作用是操作类级别的属性（如类变量）或行为（如创建类实例）。
    类变量（如 __pool、__host 等）是属于类的，所有实例共享同一份。通过 cls 可以直接访问和修改这些类变量,
    类方法可以直接通过类名调用（如 AsyncMYSQL_CZ.create_pool()），无需创建类的实例。
    '''
    @classmethod  # 有此装饰器的,第一个参数为cls,没有此装饰器的第一个参数为self
    async def create_pool(cls):
        """创建异步连接池（推荐在程序启动时调用）
        aiomysql.create_pool：aiomysql 库提供的异步函数，用于创建 MySQL 数据库连接池
        """
        cls.__pool = await aiomysql.create_pool(
            host=cls.__host,
            port=cls.__port,
            user=cls.__user,
            password=cls.__password,
            db=cls.__database,
            minsize=1,  # 最小连接数（相当于 mincached）
            maxsize=6,  # 最大连接数（相当于 maxconnections）
            autocommit=False,  # 关闭自动提交
            pool_recycle=300  # 连接回收时间（秒）
        )

    @classmethod
    async def close_pool(cls):
        """关闭连接池（推荐在程序退出时调用）"""
        if cls.__pool:
            #标记连接池为 “关闭状态”，停止接受新的连接请求,这是一个同步操作（无需 await）
            # close() 是 aiomysql.Pool 类的方法，调用后连接池会拒绝新的连接请求（如 acquire() 获取连接会失败），
            # 但不会立即关闭所有正在使用的连接
            cls.__pool.close()
            # 异步等待连接池完全关闭（所有连接被释放）
            await cls.__pool.wait_closed()

    """
    sql: str：要执行的 SQL 查询语句
    params: tuple = None：SQL 语句的参数（可选），用于填充 SQL 中的占位符（如 %s）。默认值为 None，表示无参数。
    -> 符号：这是 Python 的函数返回值类型标注语法，用于声明函数返回值的类型
    -> Optional[List[Tuple]] 表示函数返回值的类型
        成功时：返回一个 List[Tuple]（元组列表）
        失败时：返回 None（如连接池未初始化、SQL 执行错误等）
    """
    async def execute_query(self, sql: str, params: tuple = None) -> Optional[List[Tuple]]:
        """
        通用异步查询方法
        :param sql: SQL 查询语句
        :param params: 查询参数
        :return: 查询结果列表或 None（失败时）
        """
        if not self.__pool:
            raise RuntimeError("连接池未初始化，请先调用 create_pool()")
        # async with 上下文管理器：确保连接和游标在代码块执行完毕后自动释放（归还给连接池或关闭），避免资源泄漏
        # self.__pool.acquire()：从连接池中异步获取一个数据库连接（aiomysql.Connection 对象
        # as 关键字的作用是将异步上下文管理器返回的资源对象（这里是数据库连接）绑定到一个变量（conn）
        async with self.__pool.acquire() as conn:
            # conn.cursor()：通过连接创建一个游标（aiomysql.Cursor 对象），游标是执行 SQL 语句和获取结果的接口
            async with conn.cursor() as cursor:
                try:
                    # cursor.execute(sql, params)：异步执行 SQL 语句。params 用于填充 SQL 中的占位符（如 %s），
                    # 这种方式可以防止 SQL 注入攻击（替代直接拼接字符串
                    # 若 params 为 None，则 params or () 会将其转换为空元组（()），避免 execute 方法因参数缺失报错
                    await cursor.execute(sql, params or ())
                    # cursor.fetchall()：异步获取所有查询结果（即数据库返回的所有行）。返回值是一个元组列表
                    result = await cursor.fetchall()
                    return result
                except aiomysql.OperationalError as e:
                    # 处理数据库连接相关错误（如连接超时、权限不足）
                    error_code, error_msg = e.args
                    print(f"数据库操作错误 [{error_code}]: {error_msg}")
                    logger.error(f"数据库操作错误 [{error_code}]: {error_msg}")
                    if error_code in (2003, 2006, 2013):  # 连接拒绝/丢失
                        print("⚠️ 数据库连接失败，请检查主机、端口和权限")
                    return None
                except aiomysql.ProgrammingError as e:
                    # 处理SQL语法错误或参数不匹配
                    error_code, error_msg = e.args
                    print(f"SQL编程错误 [{error_code}]: {error_msg}")
                    print(f"错误SQL: {sql}")
                    print(f"参数: {params}")
                    logger.error(f"SQL编程错误 [{error_code}]: {error_msg}")
                    return None
                except aiomysql.IntegrityError as e:
                    # 处理数据完整性错误（如唯一约束冲突、外键失败）
                    error_code, error_msg = e.args
                    print(f"数据完整性错误 [{error_code}]: {error_msg}")
                    logger.error(f"数据完整性错误 [{error_code}]: {error_msg}")
                    return None
                except aiomysql.Error as e:
                    # 处理其他MySQL错误
                    error_code, error_msg = e.args
                    print(f"未知MySQL错误 [{error_code}]: {error_msg}")
                    logger.error(f"未知MySQL错误 [{error_code}]: {error_msg}")
                    return None
                except Exception as e:
                    # 处理非MySQL相关错误（如网络中断）
                    error_code, error_msg = e.args
                    print(f"执行查询时发生意外错误: {e}")
                    logger.error(f"执行查询时发生意外错误 [{error_code}]: {error_msg}")
                    return None

    async def execute_update(self, sql: str, params: tuple = None) -> bool:
        """
        通用异步更新/插入方法
        :param sql: SQL 语句
        :param params: 参数
        :return: 执行是否成功
        """
        if not self.__pool:
            raise RuntimeError("连接池未初始化，请先调用 create_pool()")

        async with self.__pool.acquire() as conn:
            async with conn.cursor() as cursor:
                try:
                    await cursor.execute(sql, params or ())
                    # 将当前事务中所有未提交的数据库更改（如插入、更新、删除）永久保存到数据库
                    await conn.commit()
                    return True
                except aiomysql.OperationalError as e:
                    error_code, error_msg = e.args
                    print(f"数据库操作错误 [{error_code}]: {error_msg}")
                    await conn.rollback() # 回滚,撤销,提交的修改
                    return False
                except aiomysql.ProgrammingError as e:
                    error_code, error_msg = e.args
                    print(f"SQL编程错误 [{error_code}]: {error_msg}")
                    print(f"错误SQL: {sql}")
                    print(f"参数: {params}")
                    await conn.rollback()# 回滚,撤销,提交的修改
                    return False
                except aiomysql.IntegrityError as e:
                    error_code, error_msg = e.args
                    print(f"数据完整性错误 [{error_code}]: {error_msg}")
                    await conn.rollback()# 回滚,撤销,提交的修改
                    return False
                except aiomysql.Error as e:
                    error_code, error_msg = e.args
                    print(f"未知MySQL错误 [{error_code}]: {error_msg}")
                    await conn.rollback()# 回滚,撤销,提交的修改
                    return False
                except Exception as e:
                    print(f"执行更新时发生意外错误: {e}")
                    await conn.rollback()# 回滚,撤销,提交的修改
                    return False

    async def execute_update(self, sql_operations: List[Tuple[str, tuple]]) -> bool:
        """
        通用异步更新/插入方法，支持多个相关操作的事务控制
        :param sql_operations: 包含SQL语句及其参数的元组列表 [(sql1, params1), (sql2, params2), ...]
        :return: 执行是否成功
        """
        if not self.__pool:
            raise RuntimeError("连接池未初始化，请先调用 create_pool()")

        async with self.__pool.acquire() as conn:
            try:
                # 开始事务
                await conn.begin()

                for sql, params in sql_operations:
                    async with conn.cursor() as cursor:
                        try:
                            await cursor.execute(sql, params or ())
                        except aiomysql.Error as e:
                            # 记录详细的错误信息
                            logger.error(f"执行SQL时出错: {sql}, 参数: {params}, 错误: {e}")
                            # 回滚事务
                            await conn.rollback()
                            logger.error("事务已回滚，原因是SQL执行错误")
                            return False

                # 所有操作成功，提交事务
                await conn.commit()
                logger.info("事务已成功提交")
                return True

            except Exception as e:
                # 记录其他异常信息
                logger.error(f"执行事务时发生意外错误: {e}")
                # 回滚事务
                await conn.rollback()
                logger.error("事务已回滚，原因是发生意外错误")
                return False


    async def jian_biao(self,sql):
        # 在脚本开头添加警告过滤器，忽略表已存在的警告：
        import warnings
        from aiomysql import Warning
        # 忽略建表时,表已经存在警告
        warnings.filterwarnings("ignore", category=Warning, message="Table.*already exists")

        if not self.__pool:
            raise RuntimeError("连接池未初始化，请先调用 create_pool()")

        async with self.__pool.acquire() as conn:
            async with conn.cursor() as cursor:
                try:
                    await cursor.execute(sql)
                    # 将当前事务中所有未提交的数据库更改（如插入、更新、删除）永久保存到数据库
                    await conn.commit()
                    print(f"操作成功")
                    return True
                except aiomysql.Error as e:
                    print(f"操作失败: {e}")
                    # 回滚当前未提交的事务
                    await conn.rollback()
                    return False


    async def jian_biao(self,sql):
        async with self.__pool.acquire() as conn:
            async with conn.cursor() as cursor:
                try:
                    await cursor.execute(sql)
                    # 将当前事务中所有未提交的数据库更改（如插入、更新、删除）永久保存到数据库
                    await conn.commit()
                    print(f"操作成功")
                    return True
                except aiomysql.Error as e:
                    print(f"操作失败: {e}")
                    # 回滚当前未提交的事务
                    await conn.rollback()
                    return False